/*
 * TCSS 558
 * Distributed HashMap
 * Fall 2013
 * James Marquardt
 * Matt Adams
 * Justin Wong
 */
package node;

import java.rmi.RemoteException;
import java.util.Set;

import model.Entry;
import model.HostPort;
import model.NodesAndEntries;

public abstract class Node {
    
    /**
     * ID of this Node.
     */
    protected int nodeID;

    /**
     * Host and port of this node.
     */
    protected HostPort nodeHostPort;
        
    /**
     * Get this node's host and port information.
     * 
     * @return Returns HostPort object for this node.
     */
    public HostPort getNodeHostPort() {
        return this.nodeHostPort;
    }
    
    /**
     * Get this node's id.
     * 
     * @return Returns this nodes id.
     */
    public int getNodeID() {
        return this.nodeID;
    }
     
    /**
     * Returns the chord node that is responsible for the given target node id.
     * 
     * @param targetNodeID The target node id.
     * @return Returns node responsible for given node id.
     */
    public abstract Node findSuccessor(final int targetNodeID);
    
    /**
     * Stores the object under its given id.
     * 
     * @param entry Entry being inserted.
     */
    public abstract void insertEntry(final Entry entry);
    
    /**
     * Removes the object based on its given id.
     * 
     * @param entry Entry being removed.
     */
    public abstract void removeEntry(final Entry entry);
    
    /**
     * Returns the entry stored at the given id.
     * 
     * @param entry
     * @return Returns Entry object stored at give id.
     */
    public abstract Entry getEntry(final int key);
    
    /**
     * Returns whether the queried object is contained in a list under the given id.
     * 
     * @param entry Entry being checked for contains.
     * @return Returns true if object is found in the list under the given id.
     */
    public abstract boolean containsEntry(final Entry entry);
    
    /**
     * Informs a node that its predecessor is leaving the chord.
     * 
     * @param predecessor Predecessor node leaving.
     */
    public abstract void leaveNetworkNotify(final Node predecessor);

    /**
     * Adds all entries in a set to this node.
     * @param allEntries All entries to be added.
     */
    public abstract void addAllEntries(Set<Entry> allEntries);
    
    /**
     * Closes the connection to the node.
     */
    public abstract void disconnect();
    
    /**
     * Requests this node's predecessor in result[0] and successor in
     * result[1]. This method is called by another node which thinks
     * it is this node's predecessor.
     * 
     * @param potentialPredecessor
     * @return A list containing the predecessor at first position of the list
     *         and the successors in the rest of the list.
     */
    public abstract NodesAndEntries notifyWithPotentialPredecessor(Node potentialPredecessor) throws RemoteException;
    
    /**
     * Sets this node's successor.
     * 
     * @param successorNode
     */
    public abstract void setSuccessor(Node successorNode);
    
    /**
     * Sets this node's host and port data.
     * 
     * @param nodeHostPort The host and port data for this node.
     */
    public void setNodeHostPort(final HostPort nodeHostPort) {
        this.nodeHostPort = nodeHostPort;
    }
    
    /**
     * Inserts a set of entry copies.
     * 
     * @param entryCopiesForInsert Entry copies to insert.
     */
    public abstract void insertCopies(final Set<Entry> entryCopiesForInsert);
        
    
    /**
     * Removes a set of entry copies.
     * 
     * @param entryCopiesForRemove Entry copies to remove.
     */
    public abstract void removeCopies(final Set<Entry> entryCopiesForRemove);
    
    /**
     * Sets this node's id.
     * 
     * @param nodeID The node id.
     */
    public void setNodeID(final int nodeID) {
        this.nodeID = nodeID;
    }
    
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + nodeID;
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Node other = (Node) obj;
        if (this.nodeID != other.getNodeID())
            return false;
        return true;
    }
    
    /**
     * @return Returns all entries this node is responsible for.
     */
    public abstract Set<Entry> getEntries();
    
    /**
     * Test connection of node.
     */
    public abstract void isLive() throws RemoteException;

}
